﻿#include "FileDialog.h"
#include "Widgets/Editor/SimpleWindow.h"
#include "Object/NewObject.h"
#include "Widgets/Window.h"
#include "Widgets/TextWidget.h"
#include "Widgets/ComboBoxWidget.h"
#include "Widgets/Windows/FileBrowserWidget.h"
#include "Widgets/Positioners/VerticalPositionerWidget.h"
#include "Widgets/Positioners/HorizontalPositionerWidget.h"
#include "Widgets/EditableTextWidget.h"
#include "Widgets/RectangleWidget.h"
#include "Widgets/ButtonWidget.h"
#include "Widgets/ButtonWidget.h"
#include "Containers/WeakObjectPtr.h"

#include "Widgets/WindowManager.h"
#include "Widgets/Windows/MessageBox.h"

//convert string like "Images(*.png,*.jpg)" to {".png",".jpg"}
//         "*.png,*.jpg" to {".png",".jpg"}
//if detect *.* then return empty vector
TVector<CString> GetExtension(const CString& InDisplayFilter)
{
    TVector<CString> Result;
    
    if(InDisplayFilter.Find(U"*.*")!=-1)
    {
        return Result;
    }

    //split by ',' and '(' and ')'
    TVector<CString> SplitResult=InDisplayFilter.SplitByMultiple({U",",U"(",U")"});
    
    for(auto& Str:SplitResult)
    {
        if(Str.StartsWith(U"*."))
        {
            Result.Add(Str.SubString(1));
        }
    }

    return Result;
}


TVector<SPath> WH::CreateOpenFileDialog(
    const CString &InTitle
    , const SPath &InDefaultPath
    , const TVector<CString> &InFilter
    ,bool MultiSelect
    )
{
    auto Window= NewObject<RWindow>();
    Window->HideSystemBorder();
    Window->SetWindowTitle(InTitle);
    Window->SetWindowSize(SIntPoint(800,600));
    Window->MoveToScreenCenter();

    auto ContentContainer=WH::AddCommonWidgets(Window.Get());

    auto VerticalPanel=NewWidget<RVerticalPositionerWidget>(ContentContainer);
    VerticalPanel->Anchor.Fill(ContentContainer);

    auto FileBrowser=NewWidget<RFileBrowserWidget>(VerticalPanel);
    FileBrowser->Anchor.HorizontalFill(VerticalPanel);
    FileBrowser->Height=470;

    auto FileNameLine=NewWidget<RHorizontalPositionerWidget>(VerticalPanel);
    FileNameLine->Anchor.HorizontalFill(VerticalPanel);
    FileNameLine->Height=30;

    auto FileNameLabel=NewWidget<RTextWidget>(FileNameLine);
    FileNameLabel->Text=U"文件名:";
    FileNameLabel->Width=60;
    FileNameLabel->VerticalAlignment=ETextVerticalAlignment::Center;
    FileNameLabel->Anchor.VerticalFill(FileNameLine);

    auto FileFilterBorder=NewWidget<RRectangleWidget>(FileNameLine);
    FileFilterBorder->Fill=false;
    FileFilterBorder->BorderSize=2;
    FileFilterBorder->BorderColor=SColor::White;
    FileFilterBorder->Width=220;
    FileFilterBorder->Anchor.RightReference=FileNameLine;
    FileFilterBorder->Anchor.RightOffset=5;
    FileFilterBorder->Anchor.VerticalFill(FileNameLine);

    TWeakObjectPtr<RFileBrowserWidget> WeakFileBrowserPtr=FileBrowser;

    auto FileFilter=NewWidget<RComboBoxWidget>(FileFilterBorder);
    FileFilter->SetOptions(InFilter);
    FileFilter->Anchor.Fill(FileFilterBorder);
    FileFilter->Anchor.LeftOffset=5;
    FileFilter->OnSelected.Bind([WeakFileBrowserPtr](const CString& SelectedText,uint32_t /*Selected Index*/ ){
        WeakFileBrowserPtr->UpdateFilter(GetExtension(SelectedText));
    });

    auto FileNameInputBorder=NewWidget<RRectangleWidget>(FileNameLine);
    FileNameInputBorder->Fill=false;
    FileNameInputBorder->BorderSize=2;
    FileNameInputBorder->BorderColor=SColor::White;
    FileNameInputBorder->Anchor.LeftReference=FileNameLabel;
    FileNameInputBorder->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Right;
    FileNameInputBorder->Anchor.LeftOffset=5;
    FileNameInputBorder->Anchor.RightReference=FileFilterBorder;
    FileNameInputBorder->Anchor.RightReferenceEdge=EHorizontalWidgetEdge::Left;
    FileNameInputBorder->Anchor.RightOffset=5;

    FileNameInputBorder->Anchor.VerticalFill(FileNameLine);

    auto FileNameInput=NewWidget<REditableTextWidget>(FileNameInputBorder);
    FileNameInput->VerticalAlignment=ETextVerticalAlignment::Center;
    FileNameInput->Anchor.Fill(FileNameInputBorder);
    FileNameInput->UpdateTextOnAccepted=true;

    TWeakObjectPtr<REditableTextWidget> WeakFileNameInput=FileNameInput;
    FileBrowser->OnFileSelectionChanged.Bind([WeakFileNameInput,WeakFileBrowserPtr](){
        auto Files=WeakFileBrowserPtr->GetSelectedFile();
        if(Files.Empty())
        {
            //donothing
            return;
        }

        CString Text;
        for(auto& File:Files)
        {
            //add '"' to avoid space in file name
            Text+=U"\"";
            Text+=File.GetFileOrDirectoryName();
            Text+=U"\" ";
        }

        WeakFileNameInput->Text=Text;
    });

    auto ButtonLine=NewWidget<RHorizontalPositionerWidget>(VerticalPanel);
    ButtonLine->Anchor.RightReference=VerticalPanel;
    ButtonLine->Height=30;
    ButtonLine->Width=220;

    TVector<SPath> Result;
    TWeakObjectPtr<RWindow> WeakWindowPtr=Window;


    auto OpenButton=NewWidget<RButtonWidget>(ButtonLine);
    OpenButton->Text=U"打开";
    OpenButton->SetHovorColor(SColor::FromHexRGB(0x444444),SColor::HalfGreen);
    OpenButton->Width=100;
    OpenButton->Anchor.VerticalFill(ButtonLine);
    OpenButton->OnClicked.BindLambda(
        [WeakWindowPtr,&Result,WeakFileBrowserPtr,WeakFileNameInput](const SMouseButtonEvent &)->bool{
        auto InputText=WeakFileNameInput->Text.Get();
        if(InputText.IsEmpty())
        {
            WH::ShowMessageBox(U"Error",U"请输入文件名");
            return true;
        }

        //find file names in string like "\"Untitled.png\" \"Have Spave.png\""
        TVector<CString> FileNames;

        //check if there is a file name without '"'
        if(InputText.Find(U"\"")==-1)
        {
            FileNames.Add(InputText);
        }
        else
        {
            int32_t StartIndex=0;
            while(true)
            {
                int32_t LeftQuoteIndex=InputText.Find(U"\"",StartIndex);
                if(LeftQuoteIndex==-1)
                {
                    break;
                }

                int32_t RightQuoteIndex=InputText.Find(U"\"",LeftQuoteIndex+1);
                if(RightQuoteIndex==-1)
                {
                    break;
                }

                FileNames.Add(InputText.SubString(LeftQuoteIndex+1,RightQuoteIndex-LeftQuoteIndex-1));
                StartIndex=RightQuoteIndex+1;
            }
        }

        for(auto& FileName:FileNames)
        {
            SPath Path=WeakFileBrowserPtr->GetCurrentDirectory();
            Path=Path/FileName;

            //check if file exist
            if(!Path.Exists())
            {
                WH::ShowMessageBox(U"Error",U"文件不存在:"+Path.ToString());
                return true;
            }

            //check if file is directory
            if(Path.IsDirectory())
            {
                WH::ShowMessageBox(U"Error",U"不能选择文件夹:"+Path.ToString());
                return true;
            }

            Result.Add(Path);
        }

        WeakWindowPtr->Close();
        return true;
    });

    auto CancelButton=NewWidget<RButtonWidget>(ButtonLine);
    CancelButton->Text=U"取消";
    CancelButton->SetHovorColor(SColor::FromHexRGB(0x444444),SColor::HalfGreen);
    CancelButton->Width=100;
    CancelButton->Anchor.VerticalFill(ButtonLine);
    CancelButton->OnClicked.BindLambda([WeakWindowPtr](const SMouseButtonEvent &)->bool{
        WeakWindowPtr->Close();
        return true;
    });

    FileBrowser->ShowContent(
        InDefaultPath
        ,GetExtension(InFilter[0])
        ,false
        ,MultiSelect
        );

    Window->Show();

    RWindowManager::Get()->MakeWindowModal(Window);

    return Result;
}

WHENGINE_API TOptional<SPath> WH::CreateSaveFileDialog(const CString &InTitle, const SPath &InDefaultPath, const CString &InFilter)
{
    auto Window= NewObject<RWindow>();
    Window->HideSystemBorder();
    Window->SetWindowTitle(InTitle);
    Window->SetWindowSize(SIntPoint(800,600));
    Window->MoveToScreenCenter();

    auto ContentContainer=WH::AddCommonWidgets(Window.Get());

    auto VerticalPanel=NewWidget<RVerticalPositionerWidget>(ContentContainer);
    VerticalPanel->Anchor.Fill(ContentContainer);

    auto FileBrowser=NewWidget<RFileBrowserWidget>(VerticalPanel);
    FileBrowser->Anchor.HorizontalFill(VerticalPanel);
    FileBrowser->Height=440;

    auto FileNameLine=NewWidget<RHorizontalPositionerWidget>(VerticalPanel);
    FileNameLine->Anchor.HorizontalFill(VerticalPanel);
    FileNameLine->Height=30;

    auto FileNameLabel=NewWidget<RTextWidget>(FileNameLine);
    FileNameLabel->Text=U"文件名:";
    FileNameLabel->Width=60;
    FileNameLabel->VerticalAlignment=ETextVerticalAlignment::Center;
    FileNameLabel->Anchor.VerticalFill(FileNameLine);

    auto FileNameInputBorder=NewWidget<RRectangleWidget>(FileNameLine);
    FileNameInputBorder->Fill=false;
    FileNameInputBorder->BorderSize=2;
    FileNameInputBorder->BorderColor=SColor::White;
    FileNameInputBorder->Anchor.LeftReference=FileNameLabel;
    FileNameInputBorder->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Right;
    FileNameInputBorder->Anchor.LeftOffset=5;
    FileNameInputBorder->Anchor.RightReference=FileNameLine;
    FileNameInputBorder->Anchor.RightOffset=5;

    FileNameInputBorder->Anchor.VerticalFill(FileNameLine);

    auto FileNameInput=NewWidget<REditableTextWidget>(FileNameInputBorder);
    FileNameInput->VerticalAlignment=ETextVerticalAlignment::Center;
    FileNameInput->Anchor.Fill(FileNameInputBorder);
    FileNameInput->UpdateTextOnAccepted=true;

    //if file browser select a file, then set file name to input
    TWeakObjectPtr<RFileBrowserWidget> WeakFileBrowserPtr=FileBrowser;
    TWeakObjectPtr<REditableTextWidget> WeakFileNameInput=FileNameInput;
    FileBrowser->OnFileSelectionChanged.Bind([WeakFileBrowserPtr,WeakFileNameInput](){
        auto Files=WeakFileBrowserPtr->GetSelectedFile();
        if(Files.Empty())
        {
            //donothing
            return;
        }

        WeakFileNameInput->Text=Files[0].GetFileOrDirectoryName();
    });

    auto FileTypeLine=NewWidget<RHorizontalPositionerWidget>(VerticalPanel);
    FileTypeLine->Anchor.HorizontalFill(VerticalPanel);
    FileTypeLine->Height=30;

    auto FileTypeLabel=NewWidget<RTextWidget>(FileTypeLine);
    FileTypeLabel->Text=U"文件类型:";
    FileTypeLabel->Width=60;
    FileTypeLabel->VerticalAlignment=ETextVerticalAlignment::Center;
    FileTypeLabel->Anchor.VerticalFill(FileTypeLine);

    auto FileFilterBorder=NewWidget<RRectangleWidget>(FileTypeLine);
    FileFilterBorder->Fill=false;
    FileFilterBorder->BorderSize=2;
    FileFilterBorder->BorderColor=SColor::White;
    FileFilterBorder->Anchor.LeftReference=FileTypeLabel;
    FileFilterBorder->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Right;
    FileFilterBorder->Anchor.LeftOffset=5;
    FileFilterBorder->Anchor.RightReference=FileTypeLine;
    FileFilterBorder->Anchor.RightOffset=5;
    FileFilterBorder->Anchor.VerticalFill(FileTypeLine);



    auto FileTypeWidget=NewWidget<RComboBoxWidget>(FileFilterBorder);
    FileTypeWidget->SetOptions({InFilter});
    FileTypeWidget->Anchor.Fill(FileFilterBorder);
    FileTypeWidget->Anchor.LeftOffset=5;

    auto ButtonLine=NewWidget<RHorizontalPositionerWidget>(VerticalPanel);
    ButtonLine->Anchor.RightReference=VerticalPanel;
    ButtonLine->Height=30;
    ButtonLine->Width=220;

    TOptional<SPath> Result;
    TWeakObjectPtr<RWindow> WeakWindowPtr=Window;

    auto SaveButton=NewWidget<RButtonWidget>(ButtonLine);
    SaveButton->Text=U"保存";
    SaveButton->SetHovorColor(SColor::FromHexRGB(0x444444),SColor::HalfGreen);
    SaveButton->Width=100;
    SaveButton->Anchor.VerticalFill(ButtonLine);

    TWeakObjectPtr<RComboBoxWidget> WeakFileTypeWidget=FileTypeWidget;
    SaveButton->OnClicked.BindLambda(
        [WeakWindowPtr,&Result,WeakFileBrowserPtr,WeakFileNameInput,WeakFileTypeWidget]
        (const SMouseButtonEvent&)->bool{
        auto InputText=WeakFileNameInput->Text.Get();
        if(InputText.IsEmpty())
        {
            WH::ShowMessageBox(U"Error",U"请输入文件名");
            return true;
        }

        TVector<CString> AvaliableExtensions= GetExtension(WeakFileTypeWidget->GetCurrentText());

        CString FileName;
        //check if file name has extension
        bool HaveExtension=false;
        for(auto& Extension:AvaliableExtensions)
        {
            if(InputText.EndsWith(Extension))
            {
                HaveExtension=true;
                break;
            }
        }
        
        if(!HaveExtension)
        {
            if(AvaliableExtensions.Empty())
            {
                FileName=InputText;
            }
            else
            {
                FileName=InputText+AvaliableExtensions[0];
            }
        }
        else
        {
            FileName=InputText;
        }

        SPath Path=WeakFileBrowserPtr->GetCurrentDirectory();
        Path=Path/FileName;

        if(Path.Exists())
        {
            WH::ShowMessageBox(U"Error",U"文件已存在:"+Path.ToString());
            return true;
        }

        Result=Path;

        WeakWindowPtr->Close();
        return true;
    });


    auto CancelButton=NewWidget<RButtonWidget>(ButtonLine);
    CancelButton->Text=U"取消";
    CancelButton->SetHovorColor(SColor::FromHexRGB(0x444444),SColor::HalfGreen);
    CancelButton->Width=100;
    CancelButton->Anchor.VerticalFill(ButtonLine);
    CancelButton->OnClicked.BindLambda([WeakWindowPtr](const SMouseButtonEvent&)->bool{
        WeakWindowPtr->Close();
        return true;
    });

    FileBrowser->ShowContent(
        InDefaultPath
        ,{}  //don't filter on save
        ,false
        ,false
        );

    Window->Show();

    RWindowManager::Get()->MakeWindowModal(Window);

    return Result;
}

WHENGINE_API TOptional<SPath> WH::CreateFolderDialog(const CString &InTitle, const SPath &InDefaultPath)
{
    auto Window= NewObject<RWindow>();
    Window->HideSystemBorder();
    Window->SetWindowTitle(InTitle);
    Window->SetWindowSize(SIntPoint(800,600));
    Window->MoveToScreenCenter();

    auto ContentContainer=WH::AddCommonWidgets(Window.Get());

    auto VerticalPanel=NewWidget<RVerticalPositionerWidget>(ContentContainer);
    VerticalPanel->Anchor.Fill(ContentContainer);

    auto FileBrowser=NewWidget<RFileBrowserWidget>(VerticalPanel);
    FileBrowser->Anchor.HorizontalFill(VerticalPanel);
    FileBrowser->Height=470;

    auto FolderNameLine = NewWidget<RWidget>(VerticalPanel);
    FolderNameLine->Anchor.HorizontalFill(VerticalPanel);
    FolderNameLine->Height=30;

    auto FolderNameLabel=NewWidget<RTextWidget>(FolderNameLine);
    FolderNameLabel->Text=U"文件夹:";
    FolderNameLabel->Width=60;
    FolderNameLabel->VerticalAlignment=ETextVerticalAlignment::Center;
    FolderNameLabel->Anchor.VerticalFill(FolderNameLine);

    auto FolderNameInputBorder=NewWidget<RRectangleWidget>(FolderNameLine);
    FolderNameInputBorder->Fill=false;
    FolderNameInputBorder->BorderSize=2;
    FolderNameInputBorder->BorderColor=SColor::White;
    FolderNameInputBorder->Anchor.LeftReference=FolderNameLabel;
    FolderNameInputBorder->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Right;
    FolderNameInputBorder->Anchor.LeftOffset=5;
    FolderNameInputBorder->Anchor.RightReference=FolderNameLine;
    FolderNameInputBorder->Anchor.RightOffset=5;

    FolderNameInputBorder->Anchor.VerticalFill(FolderNameLine);

    auto FolderNameInput=NewWidget<REditableTextWidget>(FolderNameInputBorder);
    FolderNameInput->VerticalAlignment=ETextVerticalAlignment::Center;
    FolderNameInput->Anchor.Fill(FolderNameInputBorder);
    FolderNameInput->UpdateTextOnAccepted=true;

    //if file browser select a folder, then set folder name to input
    TWeakObjectPtr<RFileBrowserWidget> WeakFileBrowserPtr=FileBrowser;
    TWeakObjectPtr<REditableTextWidget> WeakFolderNameInput=FolderNameInput;
    FileBrowser->OnFileSelectionChanged.Bind([WeakFileBrowserPtr,WeakFolderNameInput](){
        auto Folder=WeakFileBrowserPtr->GetSelectedDirectory();
        if(!Folder.HasValue())
        {
            //donothing
            return;
        }

        WeakFolderNameInput->Text=Folder->GetFileOrDirectoryName();
    });

    //if file browser change directory, then set folder name to input
    FileBrowser->OnDirectoryChanged.Bind([WeakFileBrowserPtr,WeakFolderNameInput](){
        auto Folder=WeakFileBrowserPtr->GetCurrentDirectory();
        auto FolderName=Folder.GetFileOrDirectoryName();

        //remove folder name 
        WeakFolderNameInput->Text=U"";
    });

    auto ButtonLine=NewWidget<RHorizontalPositionerWidget>(VerticalPanel);
    ButtonLine->Anchor.RightReference=VerticalPanel;
    ButtonLine->Height=30;
    ButtonLine->Width=220;

    TOptional<SPath> Result;
    TWeakObjectPtr<RWindow> WeakWindowPtr=Window;

    auto SelectButton=NewWidget<RButtonWidget>(ButtonLine);
    SelectButton->Text=U"选择文件夹";
    SelectButton->SetHovorColor(SColor::FromHexRGB(0x444444),SColor::HalfGreen);
    SelectButton->Width=100;
    SelectButton->Anchor.VerticalFill(ButtonLine);

    SelectButton->OnClicked.BindLambda(
        [WeakWindowPtr,&Result,WeakFileBrowserPtr,WeakFolderNameInput](const SMouseButtonEvent&)->bool{
        auto InputText=WeakFolderNameInput->Text.Get();

        SPath Path=WeakFileBrowserPtr->GetCurrentDirectory();
        if(InputText.IsEmpty() )
        {
            //donothing,text is current directory
        }
        else
        {
            Path=Path/InputText;

            if(!Path.Exists())
            {
                WH::ShowMessageBox(U"Error",U"文件夹不存在:"+Path.ToString());
                return true;
            }

            if(!Path.IsDirectory())
            {
                WH::ShowMessageBox(U"Error",U"不能选择文件:"+Path.ToString());
                return true;
            }
        }
      

        Result=Path;

        WeakWindowPtr->Close();
        return true;
    });


    auto CancelButton=NewWidget<RButtonWidget>(ButtonLine);
    CancelButton->Text=U"取消";
    CancelButton->SetHovorColor(SColor::FromHexRGB(0x444444),SColor::HalfGreen);
    CancelButton->Width=100;
    CancelButton->Anchor.VerticalFill(ButtonLine);
    CancelButton->OnClicked.BindLambda([WeakWindowPtr](const SMouseButtonEvent& )->bool{
        WeakWindowPtr->Close();
        return true;
    });

    FileBrowser->ShowContent(
        InDefaultPath
        ,{}  //don't filter on save
        ,true
        ,false
        );

    Window->Show();

    RWindowManager::Get()->MakeWindowModal(Window);

    return Result;
}
